package call

import (
	"dmsv/common"
	"dmsv/fclient"
	"dmsv/ivr"
	"errors"
	"github.com/beego/beego/v2/core/logs"
	"time"
)

const (
	call_cmd_answer         = "answer"
	call_cmd_record         = "record"
	call_cmd_dtmf           = "dtmf"
	call_cmd_dtmf_resp      = "dtmfrpt"
	call_cmd_satisfaction   = "satisfction"
	call_cmd_ivr_play       = "ivr"
	call_cmd_ivr_start      = "ivrstart"
	call_cmd_ivr_dtmf       = "ivrdtmf"
	call_cmd_play           = "play"
	call_cmd_play_hang      = "playend"
	call_cmd_play_wait      = "wait"
	call_cmd_play_serviceId = "service"
	call_cmd_leave_msg      = "leave"
	call_cmd_clear          = "clear"
	call_cmd_connect        = "connect"
	call_cmd_bridge         = "bridge"
	call_cmd_bridge_call    = "bridge_call"
	call_cmd_stop           = "stop"
	call_cmd_hangup         = "hangup"
	call_cmd_destroy        = "destroy"
)

func (c *CallInfo) StartIvr(handle *ivr.Handle) {

	args := &cmd_info{
		cName: call_cmd_ivr_start,
	}

	c.ivrHandlePtr = handle
	c.msgChan <- args
}

func (c *CallInfo) ErrHangUp(reason interface{}) {

	if c.IsEnd() {
		return
	}

	args := &cmd_info{
		cName: call_cmd_hangup,
		data:  reason,
	}

	if c.msgChan != nil {
		c.msgChan <- args
	} else {
		c.errHangUp(reason)
	}
}

//ivr放音
func (c *CallInfo) ivrRun(key string) {

	//跳转下个节点
	node := c.ivrHandlePtr.MoveToNext(c.GetSessionId(), key)
	if node == nil {
		logs.Error("[%v] 无匹配节点，挂机处理.", c.GetSessionId())
		c.ErrHangUp(common.SuccIvrOver)
		return
	}

	logs.Debug("%v find next node:%v with key:[ %v ]nodeType:%v 放音文件:%v,计次:%v",
		c.GetSessionId(), node.Name, key, node.NodeType, node.Play, node.Count)

	if node.Count >= 3 {
		c.ErrHangUp(common.ErrIvrTTL)
		logs.Info("[%v] 达到最大重复次数，挂机...", c.GetSessionId())
		return
	}

	media := common.MediaFullPath(c.ivrHandlePtr.AppId(), node.Play)

	c.currentNodeType = node.NodeType
	switch node.NodeType {

	case ivr.NodeTypePlay:
		c.cmdCurr = call_cmd_ivr_play
		c.cmdData = media
		fclient.PlayMediaFile(c.fCallId, media)
	case ivr.NodeTypeGetKey:

		args := DTMF_ARGS{
			MaxKey:    1,
			TimeOut:   30, //默认30s超时
			MediaFile: media,
			PlayTimes: 1,
		}

		c.CmdIvrGetKeys(args)
	case ivr.NodeTypeEnd:
		c.cmdCurr = call_cmd_play_hang
		c.cmdData = media
		fclient.PlayMediaFile(c.fCallId, media)
	case ivr.NodeTypeQueue:

		//发送入队通知
		msg := CallEvent{
			Name:   C_EVENT_TO_QUEUE,
			EvTime: time.Now(),
			Call:   c,
			Data:   node.ToQueue,
		}
		c.ssChan <- msg
	case ivr.NodeTypeService:

		//发送转坐席通知
		msg := CallEvent{
			Name:   C_EVENT_TRANSFER,
			EvTime: time.Now(),
			Call:   c,
			Data:   node.ToService,
		}
		c.ssChan <- msg

	case ivr.NodeTypeToNumber:

		c.cmdCurr = call_cmd_bridge_call
		c.cmdData = node.ToNumber

		newCallId, err := fclient.NewCallId()
		if err != nil {
			logs.Error("%v 创建uuid 失败.")
			return
		}

		//发送转坐席通知
		msg := CallEvent{
			Name:   C_EVENT_CALL_OUT,
			EvTime: time.Now(),
			Call:   c,
			Data:   node.ToNumber,
		}
		c.ssChan <- msg

		callInfo := createCall(newCallId, c.Callee, node.ToNumber, LEG_DIR_OUTCALL)
		callInfo.BindSession(c.sessionId, c.ssChan)

		//此处需要改公司外显
		fclient.BridgeCall(c.fCallId, newCallId, c.Callee, node.ToNumber)

	default:
		logs.Error("%v wrong type:%v", c.GetSessionId(), node)
		c.ErrHangUp(common.ErrSystem)
	}

}

func (c *CallInfo) Answer() {

	ev := &cmd_info{
		cName: call_cmd_answer,
	}

	c.msgChan <- ev
}

//开始录音
func (c *CallInfo) StartRecord(filePath string) {

	if c.IsEnd() {
		return
	}

	ev := &cmd_info{
		cName: call_cmd_record,
		data:  filePath,
	}

	c.msgChan <- ev
}

//停止播放
func (c *CallInfo) StopPlay(media string) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_stop,
		data:  media,
	}

	c.msgChan <- ev
}

//ivr获取按键
func (c *CallInfo) CmdIvrGetKeys(args DTMF_ARGS) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_ivr_dtmf,
		data:  args,
	}
	c.msgChan <- ev
}

//获取按键
func (c *CallInfo) CmdGetKeys(args DTMF_ARGS) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_dtmf,
		data:  args,
	}
	c.msgChan <- ev
}

//放音
func (c *CallInfo) PlayFile(mediaFile string) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_play,
		data:  mediaFile,
	}

	c.msgChan <- ev
}

//放音
func (c *CallInfo) PlayFileAndHangup(mediaFile string) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_play_hang,
		data:  mediaFile,
	}

	c.msgChan <- ev
}

//桥接通话
func (c *CallInfo) Bridge(call *CallInfo) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_bridge,
		data:  call,
	}
	c.msgChan <- ev
}

//桥接通话
func (c *CallInfo) ConnectCall(callId string) {

	if c.IsEnd() {
		return
	}
	ev := &cmd_info{
		cName: call_cmd_connect,
		data:  callId,
	}
	c.msgChan <- ev
}

//桥接外呼
func (c *CallInfo) BridgeCallToUser(caller, callee string) {

	if c.IsEnd() {
		return
	}
	args := bridgeCall{
		caller: caller,
		callee: callee,
		legDir: LEG_DIR_USER,
	}
	ev := &cmd_info{
		cName: call_cmd_bridge_call,
		data:  args,
	}

	c.msgChan <- ev
}

func (c *CallInfo) Destroy(reason interface{}) {

	ev := &cmd_info{
		cName: call_cmd_destroy,
		data:  reason,
	}
	c.msgChan <- ev
}

type WaitInfo struct {
	PlayTimes int
	Delay     int
	Media     string
	SecMedia  string
	BLeaveMsg bool
	bPlayEnd  bool
}

//播放等待音
func (c *CallInfo) PlayWait(args WaitInfo) {

	if c.IsEnd() {
		return
	}
	c.callPlay(call_cmd_play_wait, &args)
}

func (c *CallInfo) destroy() {

	if c.EndTime.IsZero() {
		logs.Warn("[%v] call [%v] is not clear", c.sessionId, c.fCallId)
	}

	if c.msgChan != nil {
		close(c.msgChan)
		c.msgChan = nil
	}

	gCalls.Delete(c.fCallId)
	logs.Debug("[%v] is clear", c.fCallId)
}

func OutCallService(callId, display, callee string, ssChan chan interface{}) (*CallInfo, error) {

	fCallId, err := fclient.CallLocalService(display, callee)
	if err != nil {
		logs.Error("[%v] 呼叫坐席 [%v] 失败:%v", callId, callee, err)
		return nil, errors.New("eCallCreate")
	}

	newCall := createCall(fCallId, display, callee, LEG_DIR_SERVICE)
	newCall.BindSession(callId, ssChan)

	return newCall, err
}

func OutCallPstn(callId, display, callee, router string, ssChan chan interface{}) (*CallInfo, error) {

	fCallId, err := fclient.OutCall(display, callee, router, 60)
	if err != nil {
		logs.Error("[%v] 呼叫坐席 [%v] 失败:%v", callId, callee, err)
		return nil, errors.New("eCallCreate")
	}

	newCall := createCall(fCallId, display, callee, LEG_DIR_SERVICE)
	newCall.BindSession(callId, ssChan)

	return newCall, err
}

func LoadSipAcct() error {
	return fclient.LoadSipAcct()
}

func DelRegAcct(acct, domain string) error {
	return fclient.DelRegAcct(acct, domain)
}
